package com.zerro.litez.runtime;

import com.zerro.litez.runtime.migration.MigrationParser;
import com.zerro.litez.runtime.migration.TableInfo;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;


public final class LitEzSupporter {

    private final String litEzTable = "LitEzInfo";
    Connection conn;


    public LitEzSupporter() {

        LitEzProperties prop = LitEzProperties.getProp();

        try {
            Class.forName(prop.getDriver_());
            conn = DriverManager.getConnection(prop.getUrl(), prop.getUsername(), prop.getPassword());
            onCreate();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void onCreate() throws SQLException {
        PreparedStatement stmt = getStmt("create table if not exists " + litEzTable + "(" +
                "tableSign varchar(256) primary key ," +
                "`sql` text," +
                "columnSigns text)", false);
        stmt.execute();
        stmt.close();
    }

    public PreparedStatement getStmt(String sql, boolean insert) throws SQLException {
        if (insert) {
            return conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        }
        return conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
    }

    List<TableInfo> oldTableInfoList = new ArrayList<>();

    public void init(List<TableInfo> tableInfoList) {
        try {
            getOldTableInfoList();
            for (TableInfo tableInfo : tableInfoList) {
                TableInfo oldTableInfo = existsTable(tableInfo.getTableSign());

                if (oldTableInfo != null) {
                    if (needUpgrade(oldTableInfo, tableInfo)) {
                        if (!tableInfo.getColumnSignStr().isEmpty()) {
                            doUpgrade(oldTableInfo, tableInfo);
                        }
                    }
                    oldTableInfoList.remove(oldTableInfo);
                } else {
                    createTable(tableInfo);
                }
            }
            for (TableInfo tableInfo : oldTableInfoList) {
                doDelete(tableInfo);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private void getOldTableInfoList() throws SQLException {
        PreparedStatement stmt = getStmt("select * from " + litEzTable, false);
        ResultSet cursor = stmt.executeQuery();
        if (cursor != null && cursor.first()) {
            do {
                oldTableInfoList.add(new TableInfo(cursor.getString(1),
                        cursor.getString(2), cursor.getString(3)));
            } while (cursor.next());
            cursor.close();
        }
        stmt.close();
    }

    public TableInfo existsTable(String sign) {
        for (TableInfo tableInfo : oldTableInfoList) {
            if (tableInfo.getTableSign().equals(sign)) {
                return tableInfo;
            }
        }
        return null;
    }

    private boolean needUpgrade(TableInfo oldTable, TableInfo newTable) {
        return !oldTable.getSql().equals(newTable.getSql());
    }


    private void doUpgrade(TableInfo oldTable, TableInfo newTable) throws SQLException {
        MigrationParser migrationParser = new MigrationParser(oldTable, newTable);

        if (!migrationParser.getSqls().isEmpty()) {
            conn.setAutoCommit(false);
            for (String sql : migrationParser.getSqls()) {
                System.out.println("upgrade sql: " + sql);
                PreparedStatement stmt = getStmt(sql, false);
                stmt.execute();
                stmt.close();
            }
            PreparedStatement stmt = getStmt("update " + litEzTable + " " +
                    "set `sql` = '" + newTable.getSql() +
                    "', `columnSigns` = '" + newTable.getColumnSignStr() +
                    "' where `tableSign` = '" + newTable.getTableSign() + '\'', false);
            stmt.execute();
            conn.commit();
        }

    }

    private void doDelete(TableInfo tableInfo) throws SQLException {
        getStmt("drop table  if exists " + tableInfo.getTableName(), false).execute();
        getStmt("delete from " + litEzTable + " where `tableSign` = '" + tableInfo.getTableSign() + "'", false).execute();
    }

    private void createTable(TableInfo tableInfo) throws SQLException {
        PreparedStatement stmt = getStmt(formatSql("insert into " + litEzTable + " values(?, ?, ?)",
                tableInfo.getTableSign(), tableInfo.getSql()
                , tableInfo.getColumnSignStr()), true);
        stmt.execute();
        stmt.close();
        stmt = getStmt(tableInfo.getSql(), false);
        stmt.execute();
        stmt.close();
    }


    private String formatSql(String sql, String... args) {
        for (String arg : args) {
            sql = sql.replaceFirst("[?]", '\'' + arg + '\'');
        }
        return sql;
    }

}
